pub mod minio_client;
pub mod songs_dao;
pub mod users_dao;
pub mod user_favorites;

use crate::config::AppConfig;
use crate::{models, utils};
use sqlx::postgres::PgPoolOptions;
use sqlx::Executor;
use sqlx::PgPool;
use tracing::info;


pub async fn connect_pg(app_config: &AppConfig) -> anyhow::Result<PgDao> {
    
    let pool = PgPoolOptions::new()
        .max_connections(5)
        .after_connect(|conn, _meta| {
            Box::pin(async move {
                conn.execute("SET TIME ZONE 'Asia/Shanghai';").await?;
                Ok(())
            })
        })
        .connect(&app_config.database_url)
        .await?;
    Ok(PgDao::new(pool)
        .init_admin(&app_config.admin_usrername, &app_config.admin_password)
        .await?)
}

#[derive(Clone)]
pub struct PgDao {
    pub songs_dao: songs_dao::SongsDao,
    pub users_dao: users_dao::UsersDao,
    pub user_favorites_dao: user_favorites::UserFavoritesDao,
}

impl PgDao {
    pub fn new(pool: PgPool) -> Self {
        let songs_dao = songs_dao::SongsDao { pool: pool.clone() };
        let users_dao = users_dao::UsersDao { pool: pool.clone()};
        let user_favorites_dao = user_favorites::UserFavoritesDao { pool };
        Self {
            songs_dao,
            users_dao,
            user_favorites_dao,
        }
    }

    pub async fn init_admin(self, user_name: &str, password: &str) -> Result<Self, anyhow::Error> {
        let exist = self
            .users_dao
            .get_user_by_username(user_name)
            .await?
            .is_some();
        if !exist {
            info!("create admin user");
            let password_hash = utils::hash_password(password)?;
            self.users_dao
                .create_user(user_name, &password_hash, models::Role::Admin)
                .await?;
        } else {
            info!("admin user already exist");
        }
        Ok(self)
    }
}
